package com.wholesmart.common.security;

import javax.servlet.http.HttpSessionListener;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import com.wholesmart.common.security.authentication.WholesmartAuthenticationFailureHandler;
import com.wholesmart.common.security.authentication.WholesmartAuthenticationSuccessHandler;
import com.wholesmart.common.security.authentication.WholesmartLogoutSuccessHandler;
import com.wholesmart.common.security.crypto.Base64Crypto;
import com.wholesmart.common.security.crypto.CipherCrypto;
import com.wholesmart.common.security.crypto.Crypto;
import com.wholesmart.common.security.crypto.SaltGenerater;
import com.wholesmart.common.security.crypto.SaltGeneraterImpl;
import com.wholesmart.common.security.filter.DecodePasswordFilter;
import com.wholesmart.common.security.properties.BrowserSecurityProperties;

/**
 * 浏览器安全配置类
 * 
 * @author dyw
 * @date 2019年10月11日
 */
@Configuration
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private WholesmartAuthenticationSuccessHandler wholesmartAuthenticationSuccessHandler;
	@Autowired
	private WholesmartAuthenticationFailureHandler wholesmartAuthenticationFailureHandler;
	@Autowired
	private UserDetailsService userDetailsService;
	@Autowired
	private DataSource dataSource;
	@Autowired
	private DecodePasswordFilter decodePasswordFilter;
	@Autowired
	private BrowserSecurityProperties browserSecurityProperties;

	/**
	 * <pre>
	 * 1、也可以实现PasswordEncoder接口以便使用自己的加密方式
	 * 
	 * 2、声明加密对象后会被框架自动注入到鉴权认证体系中
	 * 
	 * </pre>
	 * 
	 * @return 密码加密对象
	 */
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/**
	 * 系统提供默认的基于Base64的编码解码工具，该工具用于登录接口加密字段的解密
	 * 
	 * 
	 * 当没有提供默认加密解密工具时生效
	 * 
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean(Crypto.class)
	@ConditionalOnProperty(name = "wholesmart.browser.security.password-decode", havingValue = "base64")
	public Crypto base64CryptoInterface() {
		return new Base64Crypto();
	}

	@Bean
	@ConditionalOnMissingBean(Crypto.class)
	@ConditionalOnProperty(name = "wholesmart.browser.security.password-decode", havingValue = "cipher")
	public Crypto cryptoInterface() {
		return new CipherCrypto();
	}

	@Bean
	@ConditionalOnProperty(name = "wholesmart.browser.security.password-decode", havingValue = "cipher")
	public SaltGenerater saltGenerater() {
		return new SaltGeneraterImpl();
	}

	@Bean
	public HttpSessionListener httpSessionListener() {
		return new HttpSessionEventPublisher();
	}

	/**
	 * 配置退出成功处理器
	 * 
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean(LogoutSuccessHandler.class)
	public LogoutSuccessHandler logoutSuccessHandler() {
		return new WholesmartLogoutSuccessHandler();
	}

	/**
	 * Token持久化处理器
	 * 
	 * @return
	 */
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
		tokenRepositoryImpl.setDataSource(dataSource);
		return tokenRepositoryImpl;
	}

	/**
	 * <pre>
	 * 【Form-Login登陆认证】
	 * 
	 * 用于处理该方式登陆的过滤器为:
	 * 
	 * org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
	 * </pre>
	 * 
	 * @param http
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http.cors().and()

				.csrf().disable()// 关闭跨域请求限制

				.addFilterBefore(decodePasswordFilter, UsernamePasswordAuthenticationFilter.class)

				.formLogin()// 表单登陆

				.loginPage(browserSecurityProperties.getLoginPage())// 未鉴权跳转路径

				.loginProcessingUrl(browserSecurityProperties.getLoginProcessingUrl())// 请求授权路径

				.successHandler(wholesmartAuthenticationSuccessHandler)// 鉴权成功后的处理器

				.failureHandler(wholesmartAuthenticationFailureHandler) // 鉴权失败后的处理器

				.and()

				.rememberMe()

				.tokenRepository(persistentTokenRepository())

				.tokenValiditySeconds(1200)

				.userDetailsService(userDetailsService)

				.and()

				.sessionManagement()// 会话管理

				.invalidSessionUrl(browserSecurityProperties.getInvalidSessionUrl())

				.maximumSessions(1)

				// .maxSessionsPreventsLogin(true)

				.and()

				.and()

				.logout()

				.logoutUrl(browserSecurityProperties.getLogoutUrl())

				.invalidateHttpSession(true)

				.logoutSuccessHandler(logoutSuccessHandler())

				.deleteCookies("JSESSIONID").and()

				.authorizeRequests()

				.antMatchers(browserSecurityProperties.getPermitAllUrls())

				.permitAll() // 这些请求不需要权限认证

				.anyRequest()

				.permitAll(); // 这些请求不需要权限认证

		// .authenticated();

		// .access("@rbacService.hasPermission(request, authentication)");

	}

}
